#!/usr/bin/env ts-node

/**
 * Advanced features example of @roasmax/rabbitmq
 * Demonstrates retry logic, circuit breakers, validation, routing, and monitoring
 */

import {
  RabbitMQClient,
  createMessage,
  createFunctionHandler,
  createTypedHandler,
  RetryHandler,
  createCircuitBreaker,
  createMessageRouter,
  createHeaderRouter,
  createContentRouter,
  ValidationPatterns,
  globalValidator,
  createHealthChecker,
  createMonitoringSystem,
  createLoggingMiddleware,
  createMetricsMiddleware,
} from '../src';
import { z } from 'zod';

// Define custom schemas
const PaymentEventSchema = z.object({
  paymentId: z.string().uuid(),
  orderId: z.string().uuid(),
  amount: z.number().positive(),
  currency: z.string().length(3),
  status: z.enum(['pending', 'completed', 'failed', 'refunded']),
  gateway: z.string(),
  timestamp: z.string().datetime(),
});

type PaymentEvent = z.infer<typeof PaymentEventSchema>;

async function advancedExample(): Promise<void> {
  console.log('🚀 Advanced RabbitMQ Features Example');
  console.log('====================================');

  // Create client
  const client = RabbitMQClient.create({
    host: process.env.RABBITMQ_HOST || 'localhost',
    port: parseInt(process.env.RABBITMQ_PORT || '5672'),
    username: process.env.RABBITMQ_USERNAME || 'guest',
    password: process.env.RABBITMQ_PASSWORD || 'guest',
  });

  try {
    await client.initialize();
    console.log('✅ Client initialized');

    // Setup comprehensive middleware
    const pipeline = client.getMiddlewarePipeline();
    pipeline.add(createLoggingMiddleware({ logLevel: 'info' }));
    pipeline.add(createMetricsMiddleware());

    // Setup monitoring
    const connectionPool = (client as any).connectionPool;
    const healthChecker = createHealthChecker(connectionPool);
    const monitoring = createMonitoringSystem(healthChecker, {
      healthCheckInterval: 15000,
    });

    monitoring.on('alert', (alert) => {
      console.log(`🚨 ALERT: ${alert.title} - ${alert.message}`);
    });

    monitoring.start();

    // Register custom validation schemas
    globalValidator.registerSchema('paymentEvent', PaymentEventSchema);

    console.log('\n🔧 Advanced Features Demo');
    console.log('=========================');

    // 1. Circuit Breaker Example
    console.log('\n⚡ Circuit Breaker Demo');
    const circuitBreaker = createCircuitBreaker({
      failureThreshold: 3,
      recoveryTimeout: 10000,
    });

    const unreliableService = async (data: any) => {
      if (Math.random() < 0.7) { // 70% failure rate
        throw new Error('Service temporarily unavailable');
      }
      return { processed: true, data };
    };

    // Test circuit breaker
    for (let i = 1; i <= 10; i++) {
      try {
        const result = await circuitBreaker.execute(() => unreliableService({ attempt: i }));
        console.log(`  ✅ Attempt ${i}: Success`);
      } catch (error) {
        console.log(`  ❌ Attempt ${i}: ${(error as Error).message}`);
      }
    }

    console.log(`  Circuit breaker state: ${circuitBreaker.getState()}`);

    // 2. Advanced Routing Example
    console.log('\n🗺️ Advanced Routing Demo');
    
    const router = client.createRouter('advanced_events');
    await router.setupExchange();

    // Pattern-based message router
    const messageRouter = createMessageRouter();
    
    messageRouter.addRoute('payment.:status', async (message, params) => {
      console.log(`  💳 Payment ${params?.status}: ${JSON.stringify(message.body)}`);
    }, 10);

    messageRouter.addRoute('order.:action.:orderId', async (message, params) => {
      console.log(`  📦 Order ${params?.action} for ${params?.orderId}`);
    }, 5);

    messageRouter.addRoute('user.*', async (message, params) => {
      console.log(`  👤 User event: ${JSON.stringify(message.body)}`);
    }, 1);

    // Header-based router
    const headerRouter = createHeaderRouter();
    
    headerRouter.addHeaderMatch('priority', 'high', async (message) => {
      console.log(`  🔥 High priority message: ${message.id}`);
    });

    headerRouter.addHeaderMatch('source', 'mobile', async (message) => {
      console.log(`  📱 Mobile message: ${message.id}`);
    });

    // Content-based router
    const contentRouter = createContentRouter();
    
    contentRouter.addPropertyMatch('amount', 1000, async (message) => {
      console.log(`  💰 Large transaction detected: ${message.id}`);
    });

    // Combined routing handler
    const routingHandler = createFunctionHandler(async (messageBody: any, context: any) => {
      const message = context.message;
      const routingKey = message.getHeader('routingKey') as string || '';
      
      // Try pattern-based routing first
      const routed = await messageRouter.route(message, routingKey);
      if (!routed) {
        console.log(`  ❓ No pattern match for: ${routingKey}`);
      }
      
      // Always try header and content routing
      await headerRouter.routeAll(message);
      await contentRouter.routeAll(message);
      
      return { routed };
    });

    // Subscribe to all events
    await router.subscribe('#', routingHandler);

    // 3. Validation and Type Safety Example
    console.log('\n🔒 Validation Demo');
    
    const paymentQueue = client.createWorkQueue('payments');
    await paymentQueue.setupQueue();

    // Type-safe payment handler with validation
    const paymentHandler = createTypedHandler(
      PaymentEventSchema,
      async (payment: PaymentEvent) => {
        console.log(`  💳 Processing payment ${payment.paymentId}`);
        console.log(`     Amount: ${payment.amount} ${payment.currency}`);
        console.log(`     Status: ${payment.status}`);
        console.log(`     Gateway: ${payment.gateway}`);
        
        // Simulate payment processing
        await new Promise(resolve => setTimeout(resolve, 500));
        
        return { 
          processed: true, 
          paymentId: payment.paymentId,
          processedAt: new Date().toISOString() 
        };
      }
    );

    // Add retry logic to payment handler
    const retryPaymentHandler = new RetryHandler(
      paymentHandler,
      3, // max retries
      1000, // initial delay
      2 // backoff factor
    );

    await paymentQueue.startWorkers(retryPaymentHandler, 2);

    // 4. Send Test Messages
    console.log('\n📤 Sending Test Messages');
    
    // Send routing test messages
    const routingMessages = [
      { key: 'payment.completed', data: { paymentId: 'pay_123', amount: 99.99 } },
      { key: 'payment.failed', data: { paymentId: 'pay_124', reason: 'insufficient_funds' } },
      { key: 'order.created.ord_456', data: { orderId: 'ord_456', customerId: 'cust_789' } },
      { key: 'user.login', data: { userId: 'user_123', ip: '192.168.1.1' } },
    ];

    for (const msg of routingMessages) {
      const message = createMessage(msg.data)
        .withHeader('routingKey', msg.key)
        .withHeader('priority', Math.random() > 0.5 ? 'high' : 'normal')
        .withHeader('source', Math.random() > 0.5 ? 'mobile' : 'web')
        .build();

      await router.send(msg.key, msg.data);
      console.log(`  📤 Sent: ${msg.key}`);
    }

    // Send payment messages
    const paymentEvents: PaymentEvent[] = [
      {
        paymentId: '550e8400-e29b-41d4-a716-446655440001',
        orderId: '550e8400-e29b-41d4-a716-446655440002',
        amount: 1000, // Will trigger content router
        currency: 'USD',
        status: 'completed',
        gateway: 'stripe',
        timestamp: new Date().toISOString(),
      },
      {
        paymentId: '550e8400-e29b-41d4-a716-446655440003',
        orderId: '550e8400-e29b-41d4-a716-446655440004',
        amount: 49.99,
        currency: 'EUR',
        status: 'pending',
        gateway: 'paypal',
        timestamp: new Date().toISOString(),
      },
    ];

    for (const payment of paymentEvents) {
      await paymentQueue.sendTask(payment);
      console.log(`  💳 Sent payment: ${payment.paymentId}`);
    }

    // 5. Test Invalid Data (Validation)
    console.log('\n❌ Testing Validation');
    
    try {
      await paymentQueue.sendTask({
        paymentId: 'invalid-uuid', // Invalid UUID
        amount: -100, // Negative amount
        currency: 'INVALID', // Invalid currency code
        status: 'unknown', // Invalid status
      });
    } catch (error) {
      console.log(`  ✅ Validation caught invalid data: ${(error as Error).message}`);
    }

    // Wait for processing
    console.log('\n⏳ Processing messages...');
    await new Promise(resolve => setTimeout(resolve, 10000));

    // 6. Display Results
    console.log('\n📊 Results Summary');
    console.log('==================');

    // Health status
    const health = await healthChecker.checkHealth();
    console.log(`Health status: ${health.status}`);

    // Monitoring status
    const monitoringStatus = monitoring.getStatus();
    console.log(`Active alerts: ${monitoringStatus.activeAlerts}`);

    // Custom metrics
    const customMetrics = monitoring.getAllMetrics();
    console.log('Custom metrics:');
    Object.entries(customMetrics).forEach(([name, stats]) => {
      if (stats && stats.count > 0) {
        console.log(`  ${name}: ${stats.count} samples, avg: ${stats.avg.toFixed(2)}`);
      }
    });

    // Circuit breaker final state
    console.log(`Circuit breaker failures: ${circuitBreaker.getFailureCount()}`);
    console.log(`Circuit breaker state: ${circuitBreaker.getState()}`);

    console.log('\n✅ Advanced features demo completed!');

  } catch (error) {
    console.error('❌ Advanced example error:', error);
  } finally {
    // Clean up
    await client.close();
    console.log('🔒 Client closed');
  }
}

// Run the example
if (require.main === module) {
  advancedExample().catch(console.error);
}

export { advancedExample };
